package com.qingcloud.df.executor.worker;

import cn.hutool.core.io.FileUtil;
import com.qingcloud.base.remote.executor.ExecutorParam;
import com.qingcloud.df.executor.engine.context.ExecuteEngineContext;
import com.qingcloud.df.executor.enums.OpResultEnum;
import com.qingcloud.df.sdk.component.config.ExecutorConfig;
import com.qingcloud.df.sdk.component.context.CompInstContext;
import com.qingcloud.df.sdk.component.context.ConfigManager;
import com.qingcloud.df.sdk.component.context.ConfigService;
import com.qingcloud.df.sdk.component.enums.EnvEnum;
import com.qingcloud.df.sdk.component.message.response.ExecutorStatus;
import com.qingcloud.df.sdk.component.utils.ComponentCommUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.File;
import java.util.*;

/**
 * 运行中心基础 service 接口
 *
 * @author wangjinnan
 */
@Service
public class ExecutorService {
    public static final Logger logger = LoggerFactory.getLogger(ExecutorService.class);
    @Resource
    private ExecuteEngineContext executeEngineContext;
    @Resource
    private ConfigService configService;
    @Value("${qingcloud.executor.instance.configDownload}")
    private boolean configDownload;

    private Map<Integer,CompInstContext> getConfigMap(){
        if(ExecutorConfig.getEnv().equals(EnvEnum.PRO.name)){
           return  ConfigManager.getProConfig();
        } else{
            return ConfigManager.getDevConfig();
        }
    }

    public void init(){
        Map<Integer,CompInstContext> instContextMap = getConfigMap();
        Set<Integer> set = new HashSet<>();
        for (Map.Entry<Integer, CompInstContext> entry : instContextMap.entrySet()){
            CompInstContext context = entry.getValue();
            if(context.getSystemRuntimeInfo() !=null && context.getSystemRuntimeInfo().getStatus()==1){
                set.add(entry.getKey());
                start(Collections.singletonList(context.getId()), context.getEnv());
            }
        }
        logger.debug("have {} instance startup successfully!",set.size());
    }

    /**
     * 启动作业
     */
    public List<ExecutorStatus> startJob(Integer jobId, String env) {
        List<Integer> instanceIdList = getInstancesByJobId(jobId, env);
        return start(instanceIdList, env);
    }

    /**
     * 停止作业
     */
    public List<ExecutorStatus> stopJob(Integer jobId, String env) {
        List<Integer> instanceIdList = getInstancesByJobId(jobId, env);
        return stop(instanceIdList, env);
    }
    private static List<Integer> getInstancesByJobId(Integer jobId, String env) {
        String jobWorkspace = ComponentCommUtils.getJobWorkspace(jobId, env);
        File[] files = FileUtil.ls(jobWorkspace);
        List<Integer> instanceIdList = new ArrayList<>();
        //解析作业下面的所有实例ID
        for (File file : files) {
            if (file.getName().contains("_")) {
                String[] split = file.getName().split("_");
                instanceIdList.add(Integer.parseInt(split[split.length - 1]));
            }
        }
        return instanceIdList;
    }

    /**
     * 启动单个实例
     *
     * @param instanceParam
     * @return
     */
    public ExecutorStatus startInstance(ExecutorParam.InstanceParam instanceParam) {
        if (configDownload) {
            configService.receiverConfig(instanceParam);
        }
        //启动实例
        return start(Collections.singletonList(instanceParam.getInstanceId()), instanceParam.getEnv()).get(0);
    }

    /**
     * 停止单个实例
     * @param InstanceId
     * @param env
     * @return
     */
    public List<ExecutorStatus> stopInstance(Integer InstanceId, String env){
        return  stop(Collections.singletonList(InstanceId), env);
    }
    /**
     * 批量启动组件实例
     *
     * @param idList 实例ID列表
     */
    private List<ExecutorStatus> start(Collection<Integer> idList, String env) {
        List<ExecutorStatus> executorStatuses = new ArrayList<>();
        for (Integer id : idList) {
            ExecutorStatus executorStatus = new ExecutorStatus();
            try {
                //先停止，再启动，每次启动都是一次重启
                executeEngineContext.stopComponent(id,env);

                executeEngineContext.startComponent(id, env);
                executorStatus.setInstanceId(id);
                executorStatus.setExecutorResult(OpResultEnum.SUCCESS.code);
                logger.info("instance [{}] started!", id);
            } catch (Exception e) {
                executorStatus.setExecutorResult(OpResultEnum.FAIL.code);
                executorStatus.setMessage(e.getMessage());
                logger.error("load component instance error, id:{}, error message:{}", id, e.getMessage());
                e.printStackTrace();
            } finally {
                executorStatuses.add(executorStatus);
            }
        }
        return executorStatuses;
    }

    /**
     * 批量停止组件实例
     *
     * @param idList 实例ID列表
     */
    private List<ExecutorStatus> stop(List<Integer> idList, String env) {
        List<ExecutorStatus> executorStatuses = new ArrayList<>();
        for (Integer id : idList) {
            ExecutorStatus executorStatus = new ExecutorStatus();
            try {
                executeEngineContext.stopComponent(id, env);
                logger.info("instance [{}] stoped!", id);
                executorStatus.setInstanceId(id);
                executorStatus.setExecutorResult(OpResultEnum.SUCCESS.code);
            } catch (Exception e) {
                executorStatus.setExecutorResult(OpResultEnum.FAIL.code);
                executorStatus.setMessage(e.getMessage());
                logger.error("load component instance error, id:{}, error message:{}", id, e.getMessage());
                e.printStackTrace();
            } finally {
                executorStatuses.add(executorStatus);
            }
        }
        return executorStatuses;
    }

    /**
     * 清理并销毁作业
     */
    public List<ExecutorStatus> destroyJob(Integer jobId, String env) {
        List<Integer> instanceIdList = getInstancesByJobId(jobId, env);
        return destroy(instanceIdList, env);
    }
    public List<ExecutorStatus> destroy(List<Integer> idList, String env) {
        List<ExecutorStatus> executorStatuses = new ArrayList<>();
        //停止作业
        for (Integer id : idList) {
            ExecutorStatus executorStatus = new ExecutorStatus();
            try {
                executeEngineContext.destroyComponent(id,env);
                logger.info("instance [{}] destroyed!", id);
                executorStatus.setInstanceId(id);
                executorStatus.setExecutorResult(OpResultEnum.SUCCESS.code);
            } catch (Exception e) {
                executorStatus.setExecutorResult(OpResultEnum.FAIL.code);
                executorStatus.setMessage(e.getMessage());
                logger.error("destroy component instance error, id:{}, error message:{}", id, e.getMessage());
                e.printStackTrace();
            } finally {
                executorStatuses.add(executorStatus);
            }
        }
        return executorStatuses;
    }
}
